using System.Collections.Generic;
using System.Linq;
using SymbolIntegration.core.Helpers;

namespace SymbolIntegration.core.Expressions.Functions
{
    public class SubstituteFunction : Expression
    {
        private Expression m_Expr;
        private readonly Dictionary<string, Expression> m_VarValues;

        public SubstituteFunction(Expression expr, Dictionary<string, Expression> varValues)
        {
            m_Expr = expr;
            m_VarValues = varValues;
        }

        public override Expression Clone()
        {
            var clone = new SubstituteFunction(m_Expr, m_VarValues);
            InnerCopy(clone);
            return clone;
        }

        public override ExpressionType Type
        {
            get { return ExpressionType.Substitute; }
        }

        public override Expression Substitute(Dictionary<string, Expression> varValues)
        {
            return new SubstituteFunction(this, varValues);
        }

        public override Expression Differentiate(string variable)
        {
            return new DifferentiateFunction(this, variable);
        }

        public override Expression Normalize()
        {
            var clone = (SubstituteFunction) Clone();
            clone.m_Expr = m_Expr.Normalize();
            return clone;
        }

        public override bool IsEqual(Expression right)
        {
            var clone = right as SubstituteFunction;
            if (clone == null)
                return false;
            return m_Expr.IsEqual(clone.m_Expr) && IsNegate == clone.IsNegate &&
                   m_VarValues.SequenceEqual(clone.m_VarValues);
        }

        public override Polinom FormatToPolinomAsDependentFromVariable(string variable)
        {
            return null;
        }

        public override string ToString()
        {
            string result = "Subst(";
            result += m_Expr;
            foreach (var expression in m_VarValues)
            {
                result +=  ", " + expression.Key + "=>" + expression.Value;
            }

            if (IsNegate)
            {
                result = "(-" + result + ")";
            }
            return result;
        }

        protected internal override void RebuildDependancyCache()
        {
            m_Cache.IsValid = true;
            m_VarValues.Foreach(pair => pair.Value.RebuildDependancyCache());
            m_Expr.RebuildDependancyCache();
            m_Cache.Varibles.UnionWith(m_Expr.m_Cache.Varibles);
            m_Cache.Varibles.UnionWith(m_VarValues.Keys);
            m_VarValues.Foreach(pair => m_Cache.Varibles.UnionWith(pair.Value.m_Cache.Varibles));
        }

        protected internal override void FillExpressionStatistic(ExpressionStatistic statistic, string integrateVariable)
        {
            statistic.HasUnintegratedExpression = true;
            m_Expr.FillExpressionStatistic(statistic, integrateVariable);
        }

        protected internal override Expression IntegrateAsDependentFromVar(string variable, IIntegrator integrator)
        {
            return new IntegrFunction(this, variable);
        }
    }
}